﻿using System;
using System.Text;
using ACompany.OrderProcessing.Infrastructure;
using ACompany.OrderProcessing.Model;
using ACompany.OrderProcessing.Services;
using ACompany.OrderProcessing.Infrastructure.CustomExceptions;

namespace ACompany.OrderProcessing.Presentation.Customer
{
    public class CustomerPresenter
    {
        #region fields
        private readonly ICustomerView _view;
        private readonly ICustomerService _customerService;
        private Model.Customer _selectedCustomer;
        private Mode _mode;
        #endregion

        #region ctors

        public CustomerPresenter(ICustomerView view)
            : this(view, new CustomerService())
        {
        }

        private CustomerPresenter(ICustomerView view, CustomerService customerService)
        {
            _view = view;
            _customerService = customerService;
        }
        #endregion

        public void Display()
        {
            ClearInfoAndErrorMessages();
            Model.Customer customer = GetSelectedCustomerDetail();
            SetButtonText();
            SetTitleText();

            if (customer == null)
            {
                _view.ErrorMessage(string.Format("Could not find details from Customer with Id of {0}.", _view.CustomerId));
            }
            else
            {
                UpdateView(customer);
            }
        }

        private Model.Customer GetSelectedCustomerDetail()
        {
            if (_selectedCustomer == null)
            {
                if (_view.CustomerId == Guid.Empty)
                {
                    //add mode
                    _selectedCustomer = new Model.Customer();
                    _mode = Mode.Add;
                }
                else
                {
                    //edit mode
                    _selectedCustomer = _customerService.FindBy(_view.CustomerId);
                    _mode = Mode.Edit;
                }
            }
            return _selectedCustomer;
        }

        private void SetTitleText()
        {
            _view.ViewTitle(_mode == Mode.Add ? "Add Customer" : "Edit Customer");
        }

        private void SetButtonText()
        {
            _view.SaveButtonText = _mode == Mode.Add ? "Add customer" : "Save Customer";
        }

        private void ClearInfoAndErrorMessages()
        {
            _view.InfoMessage(string.Empty);
            _view.ErrorMessage(string.Empty);
        }

        private void UpdateView(Model.Customer customer)
        {
            _view.Name = customer.Name;
            _view.Email = customer.Email;
            if (_selectedCustomer.Address != null)
            {
                _view.Street = _selectedCustomer.Address.Street;
                _view.City = _selectedCustomer.Address.City;
                _view.Country = _selectedCustomer.Address.Country;
                _view.PostCode = _selectedCustomer.Address.PostCode;
            }
            else
            {
                _view.Street = _view.City = _view.Country = _view.PostCode = string.Empty;
            }
        }

        public void SaveCustomer()
        {
            Model.Customer customer = GetSelectedCustomerDetail();
            ClearInfoAndErrorMessages();

            try
            {
                UpdateFromView(customer);

                if (customer.GetBrokenRules().Count == 0)
                {
                    try
                    {
                        this._customerService.Save(customer);

                        if (_mode == Mode.Add)
                        {
                            this._view.InfoMessage(string.Format("Customer '{0}' has been added", customer.Name));
                            //NavigationService.NavigateTo("customers")
                            ClearView();
                        }
                        else
                        {
                            this._view.InfoMessage("Customer has been saved");
                        }
                    }
                    catch (Exception ex)
                    {
                        string exceptionMessage = string.Format("A problem occurred while saving customer '{0}'. {1}{2}", customer.Name, Environment.NewLine, ex.Message);
                        _view.ErrorMessage(exceptionMessage);
                    }
                }
                else
                {
                    DisplayErrorsIn(customer);
                }
            }
            catch (ValueObjectValidationException ex)
            {
                _view.ErrorMessage(ex.Message);
            }

        }

        private void ClearView()
        {
            _view.Name = string.Empty;
            _view.Email = string.Empty;

            _view.Street = string.Empty;
            _view.City = string.Empty;
            _view.Country = string.Empty;
            _view.PostCode = string.Empty;
        }


        private void DisplayErrorsIn(Model.Customer customer)
        {
            StringBuilder sb = new StringBuilder();

            sb.Append("There were some problems when trying to save this Customer:");
            sb.Append(Environment.NewLine);
            sb.Append(Environment.NewLine);

            foreach (BrokenRule brokenRule in customer.GetBrokenRules())
            {
                sb.Append(brokenRule.Rule);
                sb.Append(Environment.NewLine);
            }
            _view.ErrorMessage(sb.ToString());
        }

        private void UpdateFromView(Model.Customer customer)
        {
            customer.Name = _view.Name;
            customer.Email = _view.Email;
            customer.Address = new Address(_view.Street, _view.City, _view.Country, _view.PostCode); 
        }
    }
}
